/*


usage:

p = new Player({
  useWorker: <bool>,
  workerFile: <defaults to "Decoder.js"> // give path to Decoder.js
  webgl: true | false | "auto" // defaults to "auto"
});

// canvas property represents the canvas node
// put it somewhere in the dom
p.canvas;

p.webgl; // contains the used rendering mode. if you pass auto to webgl you can see what auto detection resulted in

p.decode(<binary>);


*/



// universal module definition
(function(root, factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD. Register as an anonymous module.
    define(["./Decoder", "./YUVCanvas"], factory);
  } else if (typeof exports === 'object') {
    // Node. Does not work with strict CommonJS, but
    // only CommonJS-like environments that support module.exports,
    // like Node.
    module.exports = factory(require("./Decoder"), require("./YUVCanvas"));
  } else {
    // Browser globals (root is window)
    root.Player = factory(root.Decoder, root.YUVCanvas);
  }
}(this, function(Decoder, WebGLCanvas) {
  "use strict";


  var nowValue = Decoder.nowValue;


  var Player = function(parOptions) {
    var self = this;
    this._config = parOptions || {};

    this.render = true;
    if (this._config.render === false) {
      this.render = false;
    };

    this.nowValue = nowValue;

    this._config.workerFile = this._config.workerFile || "Decoder.js";
    if (this._config.preserveDrawingBuffer) {
      this._config.contextOptions = this._config.contextOptions || {};
      this._config.contextOptions.preserveDrawingBuffer = true;
    };

    var webgl = "auto";
    if (this._config.webgl === true) {
      webgl = true;
    } else if (this._config.webgl === false) {
      webgl = false;
    };

    if (webgl == "auto") {
      webgl = true;
      try {
        if (!window.WebGLRenderingContext) {
          // the browser doesn't even know what WebGL is
          webgl = false;
        } else {
          var canvas = document.createElement('canvas');
          var ctx = canvas.getContext("webgl");
          if (!ctx) {
            // browser supports WebGL but initialization failed.
            webgl = false;
          };
        };
      } catch (e) {
        webgl = false;
      };
    };

    this.webgl = webgl;

    // choose functions
    if (this.webgl) {
      this.createCanvasObj = this.createCanvasWebGL;
      this.renderFrame = this.renderFrameWebGL;
    } else {
      this.createCanvasObj = this.createCanvasRGB;
      this.renderFrame = this.renderFrameRGB;
    };


    var lastWidth;
    var lastHeight;
    var onPictureDecoded = function(buffer, width, height, infos) {
      // width = 1000;
      // height = 500;
      // console.log(width, height,self.canvasObj.webGLCanvas,self.canvasObj.canvas)
      // self.canvasObj.webGLCanvas.width = 1000;
      // self.canvasObj.webGLCanvas.height = 500;
      // self.canvasObj.canvas.width = 1000;
      // self.canvasObj.canvas.height = 500;
      self.onPictureDecoded(buffer, width, height, infos);

      var startTime = nowValue();

      if (!buffer || !self.render) {
        return;
      };
      // console.log(self.canvasObj.webGLCanvas);
      self.renderFrame({
        canvasObj: self.canvasObj,
        data: buffer,
        width: width,
        height: height
      });

      if (self.onRenderFrameComplete) {
        self.onRenderFrameComplete({
          data: buffer,
          width: width,
          height: height,
          infos: infos,
          canvasObj: self.canvasObj
        });
      };

    };

    // provide size

    if (!this._config.size) {
      this._config.size = {};
    };
    this._config.size.width = this._config.size.width || 200;
    this._config.size.height = this._config.size.height || 200;
    console.log(this._config)
    if (this._config.useWorker) {
      var worker = new Worker(this._config.workerFile);
      this.worker = worker;
      worker.addEventListener('message', function(e) {
        var data = e.data;
        console.log(data);
        if (data.consoleLog) {
          console.log(data.consoleLog);
          return;
        };

        onPictureDecoded.call(self, new Uint8Array(data.buf, 0, data.length), data.width, data.height, data.infos);

      }, false);

      worker.postMessage({
        type: "Broadway.js - Worker init",
        options: {
          rgb: !webgl,
          memsize: this.memsize,
          reuseMemory: this._config.reuseMemory ? true : false
        }
      });

      if (this._config.transferMemory) {
        this.decode = function(parData, parInfo) {
          // no copy
          // instead we are transfering the ownership of the buffer
          // dangerous!!!

          worker.postMessage({ buf: parData.buffer, offset: parData.byteOffset, length: parData.length, info: parInfo }, [parData.buffer]); // Send data to our worker.
        };

      } else {
        this.decode = function(parData, parInfo) {
          // Copy the sample so that we only do a structured clone of the
          // region of interest
          var copyU8 = new Uint8Array(parData.length);
          copyU8.set(parData, 0, parData.length);
          worker.postMessage({ buf: copyU8.buffer, offset: 0, length: parData.length, info: parInfo }, [copyU8.buffer]); // Send data to our worker.
        };

      };

      if (this._config.reuseMemory) {
        this.recycleMemory = function(parArray) {
          //this.beforeRecycle();
          worker.postMessage({ reuse: parArray.buffer }, [parArray.buffer]); // Send data to our worker.
          //this.afterRecycle();
        };
      }

    } else {

      this.decoder = new Decoder({
        rgb: !webgl
      });
      this.decoder.onPictureDecoded = onPictureDecoded;

      this.decode = function(parData, parInfo) {
        self.decoder.decode(parData, parInfo);
      };

    };



    if (this.render) {
      this.canvasObj = this.createCanvasObj({
        contextOptions: this._config.contextOptions
      });
      this.canvas = this.canvasObj.canvas;
    };

    this.domNode = this.canvas;

    lastWidth = this._config.size.width;
    lastHeight = this._config.size.height;

  };

  Player.prototype = {

    onPictureDecoded: function(buffer, width, height, infos) {},

    // call when memory of decoded frames is not used anymore
    recycleMemory: function(buf) {},
    /*beforeRecycle: function(){},
    afterRecycle: function(){},*/

    // for both functions options is:
    //
    //  width
    //  height
    //  enableScreenshot
    //
    // returns a object that has a property canvas which is a html5 canvas
    createCanvasWebGL: function(options) {
      var canvasObj = this._createBasicCanvasObj(options);
      canvasObj.contextOptions = options.contextOptions;
      return canvasObj;
    },

    createCanvasRGB: function(options) {
      var canvasObj = this._createBasicCanvasObj(options);
      return canvasObj;
    },

    // part that is the same for webGL and RGB
    _createBasicCanvasObj: function(options) {
      options = options || {};
      var obj = {};
      var width = options.width;
      if (!width) {
        width = this._config.size.width;
      };
      var height = options.height;
      if (!height) {
        height = this._config.size.height;
      };
      obj.canvas = document.createElement('canvas');
      obj.canvas.width = width;
      obj.canvas.height = height;
      obj.canvas.style.backgroundColor = "#0D0E1B";

      console.log(obj.canvas);
      return obj;
    },

    // options:
    //
    // canvas
    // data
    renderFrameWebGL: function(options) {

      var canvasObj = options.canvasObj;
      // console.log(options)
      var width = options.width || canvasObj.canvas.width;
      var height = options.height || canvasObj.canvas.height;
      // var width = 1000;
      // var height = 500;
      if (canvasObj.canvas.width !== width || canvasObj.canvas.height !== height || !canvasObj.webGLCanvas) {
        canvasObj.canvas.width = width;
        canvasObj.canvas.height = height;
        canvasObj.webGLCanvas = new WebGLCanvas({
          canvas: canvasObj.canvas,
          contextOptions: canvasObj.contextOptions,
          width: width,
          height: height
        });
      };

      var ylen = width * height;
      var uvlen = (width / 2) * (height / 2);

      canvasObj.webGLCanvas.drawNextOutputPicture({
        yData: options.data.subarray(0, ylen),
        uData: options.data.subarray(ylen, ylen + uvlen),
        vData: options.data.subarray(ylen + uvlen, ylen + uvlen + uvlen)
      });

      var self = this;
      self.recycleMemory(options.data);

    },
    renderFrameRGB: function(options) {
      var canvasObj = options.canvasObj;

      var width = options.width || canvasObj.canvas.width;
      var height = options.height || canvasObj.canvas.height;

      if (canvasObj.canvas.width !== width || canvasObj.canvas.height !== height) {
        canvasObj.canvas.width = width;
        canvasObj.canvas.height = height;
      };

      var ctx = canvasObj.ctx;
      var imgData = canvasObj.imgData;

      if (!ctx) {
        canvasObj.ctx = canvasObj.canvas.getContext('2d');
        ctx = canvasObj.ctx;

        canvasObj.imgData = ctx.createImageData(width, height);
        imgData = canvasObj.imgData;
      };

      imgData.data.set(options.data);
      ctx.putImageData(imgData, 0, 0);
      var self = this;
      self.recycleMemory(options.data);

    }

  };
  // console.log('this is Player>>>', Player);
  return Player;

}));
// console.log('this is Player>>>', Player);
// export default Player